#ifndef LIBWHICH_H
#define LIBWHICH_H

#ifdef __cplusplus
extern "C" {
#endif

/*
 * 查找可执行文件在系统中的路径
 * 参数:
 *   filename - 要查找的可执行文件名
 *   buffer   - 用于存储结果的缓冲区
 *   bufsize  - 缓冲区大小
 * 返回值:
 *   成功返回指向buffer的指针，失败返回NULL
 */
char* libwhich(const char* filename, char* buffer, int bufsize);

#ifdef __cplusplus
}
#endif

#endif // LIBWHICH_H

#ifdef LIBWHICH_IMPLEMENTATION

#include <stdlib.h>
#include <string.h>
#include <stdio.h>

#ifdef _WIN32
#include <windows.h>
#include <io.h>
#define access _access
#define F_OK 0
#else
#include <unistd.h>
#include <sys/stat.h>
#endif

// 辅助函数：检查文件是否存在且可执行
static int is_executable(const char* path) {
#ifdef _WIN32
    // Windows系统检查文件是否存在
    return access(path, F_OK) == 0;
#else
    // Unix-like系统检查文件是否存在且可执行
    struct stat st;
    if (stat(path, &st) != 0)
        return 0;
    return (st.st_mode & S_IXUSR) || (st.st_mode & S_IXGRP) || (st.st_mode & S_IXOTH);
#endif
}

// 辅助函数：获取路径分隔符（PATH环境变量中分隔目录的符号）
static char get_path_separator() {
#ifdef _WIN32
    return ';';
#else
    return ':';
#endif
}

// 辅助函数：获取目录分隔符（路径中分隔目录的符号）
static char get_dir_separator() {
#ifdef _WIN32
    return '\\';
#else
    return '/';
#endif
}

// 检查文件名是否包含扩展名
static int has_extension(const char* filename) {
    const char* dot = strrchr(filename, '.');
    return dot != NULL && dot != filename && *(dot + 1) != '\0';
}

char* libwhich(const char* filename, char* buffer, int bufsize) {
    if (!filename || !buffer || bufsize <= 0)
        return NULL;

    // 获取PATH环境变量
    const char* path_env = getenv("PATH");
    if (!path_env)
        return NULL;

    // 复制PATH以便处理
    char* path = strdup(path_env);
    if (!path)
        return NULL;

    char* result = NULL;
    char sep[2] = {get_path_separator(), '\0'};
    char dir_sep = get_dir_separator();

    // 拆分PATH中的各个目录
    char* dir = strtok(path, sep);
    while (dir != NULL) {
        size_t dir_len = strlen(dir);
        size_t file_len = strlen(filename);
        int need_sep = (dir_len > 0 && dir[dir_len - 1] != dir_sep) ? 1 : 0;

        // 检查缓冲区是否足够
        if (dir_len + need_sep + file_len + 1 > (size_t)bufsize) {
            dir = strtok(NULL, sep);
            continue;
        }

        // 构建完整路径
        strcpy(buffer, dir);
        if (need_sep) {
            buffer[dir_len] = dir_sep;
            strcpy(buffer + dir_len + 1, filename);
        } else {
            strcpy(buffer + dir_len, filename);
        }

        // 检查文件是否存在且可执行
        if (is_executable(buffer)) {
            result = buffer;
            break;
        }

#ifdef _WIN32
        // Windows系统需要检查常见的可执行文件扩展名
        if (!has_extension(filename)) {
            const char* exts[] = {".exe", ".com", ".bat", ".cmd", ".ps1", NULL};
            for (int i = 0; exts[i] != NULL; i++) {
                size_t ext_len = strlen(exts[i]);
                if (dir_len + need_sep + file_len + ext_len + 1 > (size_t)bufsize)
                    continue;

                // 构建带扩展名的路径
                strcpy(buffer, dir);
                if (need_sep) {
                    buffer[dir_len] = dir_sep;
                    strcpy(buffer + dir_len + 1, filename);
                } else {
                    strcpy(buffer + dir_len, filename);
                }
                strcat(buffer, exts[i]);

                if (is_executable(buffer)) {
                    result = buffer;
                    goto cleanup; // 找到后跳出所有循环
                }
            }
        }
#endif

        dir = strtok(NULL, sep);
    }

cleanup:
    free(path);
    return result;
}

#endif // LIBWHICH_IMPLEMENTATION

// 示例主程序，定义LIBWHICH_MAIN可编译为独立工具
#ifdef LIBWHICH_MAIN
#include <stdio.h>

int main(int argc, char* argv[]) {
    if (argc != 2) {
        fprintf(stderr, "用法: %s <命令名>\n", argv[0]);
        return 1;
    }

    char buffer[1024];
    char* path = libwhich(argv[1], buffer, sizeof(buffer));
    
    if (path) {
        printf("%s\n", path);
        return 0;
    } else {
        fprintf(stderr, "%s: 未找到命令\n", argv[1]);
        return 1;
    }
}
#endif
